/* 
 * Shuriken is the legal property of its developers. Please refer to the
 * COPYRIGHT file distributed with this
 * source distribution.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

using System;
using System.Collections.Generic;
using System.Text;
using Shuriken.Core.Utils;
using Shuriken.Core.Ranking;
using Shuriken.Base; 

namespace Shuriken.Core.Store
{
    public class Shell32FolderItem : ISubject, IStoreItem, ISearchable
    {
        protected Shell32.FolderItem m_folderItem;

        protected static string IMAGE_NOT_LOADED = string.Empty;
        protected static string DEFAULT_IMAGE = string.Empty;
        protected string m_ImageIndex = IMAGE_NOT_LOADED;

        private double m_Rank;
        private string m_SearchTerm; 
        private Shuriken.Core.Ranking.MutableIndexSet m_HitMask;
        private IStore m_Store;

        static Shell32FolderItem()
        {
            DEFAULT_IMAGE = ImageStore.GetDefaultSubjectImage();
        }

        public Shell32FolderItem()
        {
            m_folderItem = null;
        }

        public Shell32FolderItem(Shell32.FolderItem folderItem) : base()
        {
            if (folderItem == null)
            {
                throw new Exception("Folder Item passed to constructor is null!");
            }

            m_folderItem = folderItem;
            // m_Store = store; 
        }

        public Shell32FolderItem(Shell32FolderItem item)
        {
            System.Diagnostics.Trace.Assert(item != null, "Container constructor called with null parameter!");
            m_folderItem = item.m_folderItem;
            m_ImageIndex = item.m_ImageIndex; 
        }

        /// <summary>
        /// Display name for this itme
        /// </summary>
        public virtual string Name
        {
            get 
            {
                return m_folderItem.Name;
            }
        }

        public string Description
        {
            get
            {
                return this.m_Store.StoreName + "\\" + this.Name; 
            }
        }

        /// <summary>
        /// Image loaded
        /// </summary>
        /// <returns>true if the image is already loaded</returns>
        public bool IsImageLoaded()
        {
            return m_ImageIndex != IMAGE_NOT_LOADED;
        }

        /// <summary>
        /// Image Index, -1 if it is not yet loaded
        /// </summary>
        public string Icon
        {
            get
            {
                if (!IsImageLoaded())
                {
                    m_ImageIndex = DEFAULT_IMAGE; 
                }

                return m_ImageIndex;
            }

            set
            {
                m_ImageIndex = value; 
            }
        }

        
        /// <summary>
        /// Exposes the Shell32.FolderItem stored in the class 
        /// </summary>
        internal Shell32.FolderItem FolderItem
        {
            get
            {
                return m_folderItem; 
            }
        }

        #region Action Implementations

        /// <summary>
        /// Executes the Subject 
        /// </summary>
        public virtual void ActionExecute()
        {
            if (FolderItem != null)
            {
                ShellUtils.LaunchFolderItem(FolderItem);
            }
        }

        /// <summary>
        /// Copies the Subject to the clipboard 
        /// </summary>
        public virtual void ActionCopyTo()
        {
            string path = ShellUtils.GetFolderItemPath(FolderItem);
            System.Windows.Forms.Clipboard.SetText(path);
        }

        /// <summary>
        /// Reveals the subject location 
        /// </summary>
        /// <remarks>Invokes the shell and selects the file</remarks>
        public virtual void ActionReveal()
        {

            if (FolderItem != null)
            {
                string path = FolderItem.Path;
                if (FolderItem.IsLink)
                {
                    if (path.EndsWith(".url") || path.EndsWith(".appref-ms"))
                    {
                        System.Diagnostics.Process.Start("explorer.exe", "/n,/select," + path);
                    }
                    else
                    {
                        path = ShellUtils.GetFolderItemPath(FolderItem);
                        System.Diagnostics.Process.Start("explorer.exe", "/n,/select," + path);
                    }
                }
                else
                {
                    if (!String.IsNullOrEmpty(path) && System.IO.File.Exists(path))
                    {
                        System.Diagnostics.Process.Start("explorer.exe", "/n,/select," + path);
                    }
                }
            }
        }

        /// <summary>
        /// Deletes the subject item 
        /// </summary>
        /// <remarks>
        /// Removes it from the store and removes the item what enabled the subject to enter the store
        /// If this is a link then it removes the link
        /// </remarks>
        public virtual void ActionDelete()
        {
            if (FolderItem != null)
            {
                string path = FolderItem.Path;

                if (System.IO.File.Exists(path))
                {
                    System.IO.File.Delete(path);
                    RemoveItemFromStore();
                }
            }
        }

        #endregion


        #region ISubject Members

        public List<Shuriken.Base.IAction> GetListOfActions()
        {
            List<IAction> listOfActions = new List<IAction>();
            ActionManager.GetDefaultInstance().GetListOfActions(this.GetType(), listOfActions);
            return listOfActions;
        }

        /// <summary>
        /// Executes the default action for this item
        /// </summary>
        public void ExecuteDefaultAction()
        {
            IAction action = ActionManager.GetDefaultInstance().GetDefaultAction(this.GetType());
            action.Execute(this);
        }

        #endregion

        #region IStoreItem Members

        /// <summary>
        /// Store where the item exists
        /// </summary>
        public IStore Store
        {
            get
            {
                return m_Store;
            }
            set
            {
                m_Store = value;
            }
        }

        /// <summary>
        /// Removes the item from its store.
        /// </summary>
        public void RemoveItemFromStore()
        {
            System.Diagnostics.Trace.Assert(Store != null, "Store cannot be null!");
            Store.RemoveItem(this);
            Store = null;
        }

        /// <summary>
        /// Register parent's action for this type. 
        /// </summary>
        /// <remarks>
        /// Register parent's action for this type. These actions are coming 
        /// from the parent classes. 
        /// </remarks>
        public virtual void RegisterParentActions()
        {
            List<IAction> actions = new List<IAction>();
            Type regType = this.GetType();
            Type baseType = regType.BaseType;

            // BaseFolderItem is not going to have any actions 
            // associated to it, so let's skip this type
            // if (baseType == typeof(BaseStoreItem))
            if(baseType == typeof(System.Object))
            {
                return;
            }

            ActionManager.GetDefaultInstance().GetListOfActions(baseType, actions);
            System.Diagnostics.Debug.Assert(actions.Count != 0, "No Action was returned for parent type!");
            ActionManager.GetDefaultInstance().RegisterActions(regType, actions);
        }

        /// <summary>
        /// Register actions for this type
        /// </summary>
        public virtual void RegisterActions()
        {
            Shell32FolderItemCopyToAction copy = new Shell32FolderItemCopyToAction();
            Shell32FolderItemOpenAction open = new Shell32FolderItemOpenAction();
            Shell32FolderItemRevealAction reveal = new Shell32FolderItemRevealAction();
            Shell32FolderItemDeleteAction delete = new Shell32FolderItemDeleteAction();

            open.RegisterAction();
            copy.RegisterAction();
            reveal.RegisterAction();
            delete.RegisterAction();
        }

        #endregion

        #region ISearchable Members

        /// <summary>
        /// Rank for the item. 
        /// </summary>
        public double Rank
        {
            get
            {
                return m_Rank;
            }

            set
            {
                m_Rank = value;
            }
        }

        /// <summary>
        /// HitMask for this item
        /// </summary>
        public Shuriken.Core.Ranking.MutableIndexSet HitMask
        {
            get
            {
                return m_HitMask;
            }
            set
            {
                m_HitMask = value;
            }
        }

        /// <summary>
        /// Last search term used to select this item 
        /// </summary>
        public string SearchTerm
        {
            get
            {
                return m_SearchTerm;
            }
            set
            {
                m_SearchTerm = value;
            }
        }

        /// <summary>
        /// Unique id
        /// </summary>
        public string UniqueIdentifier
        {
            get
            {
                return string.Format("{0}.{1}", this.GetType(), this.Name);
            }
        }

        #endregion

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(this.UniqueIdentifier);
            sb.Append("{Rank=");
            sb.Append(Rank);
            sb.Append(",SearchTerm=");
            sb.Append(SearchTerm);
            sb.Append("}");

            return sb.ToString();
        }
    }

    public abstract class Shell32FolderItemBaseAction : BaseAction 
    {
        /// <summary>
        /// Executes this action 
        /// </summary>
        /// <param name="subject">subject ot execute on</param>
        public override void Execute(ISubject subject)
        {
            if (subject is Shell32FolderItem)
            {
                Shell32FolderItem item = (Shell32FolderItem)subject;
                Execute(item);
            }
            else
            {
                throw new Exception("Wrong type of subject passed to action!");
            }
        }

        /// <summary>
        /// Executes this action 
        /// </summary>
        /// <param name="subject">subject to execute on</param>
        public abstract void Execute(Shell32FolderItem subject);

        public override bool CanExecuteOn(ISubject subject)
        {
            return subject is Shell32FolderItem;
        }
    }

    #region Action definitions
    [DefaultAction]
    [ActionName("Open")]
    [ActionSubjectType(typeof(Shell32FolderItem))]
    public class Shell32FolderItemOpenAction : Shell32FolderItemBaseAction
    {
        /// <summary>
        /// Executes this action 
        /// </summary>
        /// <param name="subject">subject to execute on</param>
        public override void Execute(Shell32FolderItem subject)
        {
            subject.ActionExecute();
        }

        public override bool CanExecuteOn(ISubject subject)
        {
            return subject is Shell32FolderItem;
        }
    }

    [ActionName("Reveal")]
    [ActionSubjectType(typeof(Shell32FolderItem))]
    public class Shell32FolderItemRevealAction : Shell32FolderItemBaseAction
    {
        /// <summary>
        /// Executes this action 
        /// </summary>
        /// <param name="subject">subject to execute on</param>
        /// <remarks>
        /// Check out if this is a .url the reveal the .url file, otherwise reveal the pointed file. 
        /// </remarks>
        public override void Execute(Shell32FolderItem subject)
        {
            subject.ActionReveal();
        }
    }


    [ActionName("Copy to (Clipboard)")]
    [ActionSubjectType(typeof(Shell32FolderItem))]
    public class Shell32FolderItemCopyToAction : Shell32FolderItemBaseAction
    {
        /// <summary>
        /// Executes this action 
        /// </summary>
        /// <param name="subject">subject to execute on</param>
        public override void Execute(Shell32FolderItem subject)
        {
            subject.ActionCopyTo();
        }


    }

    [ActionName("Delete (Shortcut)")]
    [ActionSubjectType(typeof(Shell32FolderItem))]
    public class Shell32FolderItemDeleteAction : Shell32FolderItemBaseAction
    {
        /// <summary>
        /// Executes this action 
        /// </summary>
        /// <param name="subject">subject to execute on</param>
        public override void Execute(Shell32FolderItem subject)
        {
            subject.ActionDelete();
        }

        public override bool CanExecuteOn(ISubject subject)
        {
            return subject is Shell32FolderItem;
        }
    }
    #endregion
}
